package com.yzkj.siot.facade.impl;

import cn.hutool.core.lang.UUID;
import cn.hutool.json.JSONUtil;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.yzkj.siot.context.CurUserCtx;
import com.yzkj.siot.domain.TenantDevice;
import com.yzkj.siot.domain.TenantProduct;
import com.yzkj.siot.exp.BizExp;
import com.yzkj.siot.facade.DeviceFacade;
import com.yzkj.siot.facade.ProductFacade;
import com.yzkj.siot.result.PageParams;
import com.yzkj.siot.result.PageResponse;
import com.yzkj.siot.service.TenantDeviceService;
import com.yzkj.siot.service.TenantProductService;
import com.yzkj.siot.util.PageHelper;
import com.yzkj.siot.util.RedisUtil;
import com.yzkj.siot.vo.RadioDataItem;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import org.springframework.util.StringUtils;

import javax.annotation.Resource;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

@Slf4j
@Service
public class DeviceFacadeImpl implements DeviceFacade {

    @Autowired
    TenantDeviceService deviceService;

    @Autowired
    TenantProductService productService;

    @Autowired
    ProductFacade productFacade;

    @Autowired
    PageHelper<TenantDevice> devicePageHelper;

    @Resource
    RedisUtil redisUtil;

    @Value("${redisKey.device-detail}")
    private String deviceDetailRedisKey;

    @Override
    public PageResponse<TenantDevice> page(PageParams<TenantDevice> pageParams) {

        TenantDevice where = pageParams.getEntity();

        // 构造queryWrapper
        QueryWrapper<TenantDevice> deviceQueryWrapper = new QueryWrapper<>();

        if (where != null) {
            deviceQueryWrapper.lambda()
                    .eq(where.getStatus() != null && where.getStatus() != 0, TenantDevice::getStatus, where.getStatus())
                    .like(!StringUtils.isEmpty(where.getUniqueCode()), TenantDevice::getUniqueCode, where.getUniqueCode())
                    .like(!StringUtils.isEmpty(where.getDeviceName()), TenantDevice::getDeviceName, where.getDeviceName())
                    .like(!StringUtils.isEmpty(where.getIpAddr()), TenantDevice::getIpAddr, where.getIpAddr())
                    .eq(where.getProductId() != null && where.getProductId() != 0, TenantDevice::getProductId, where.getProductId())
            ;
        }

        pageParams.getOrderBy().forEach(item -> deviceQueryWrapper.orderBy(true, item.getIsAsc(), item.getField()));

        // 查询
        PageResponse<TenantDevice> pageResponse = devicePageHelper.queryPageOrList(deviceService.getBaseMapper(), pageParams, deviceQueryWrapper);

        // 查询产品信息
        Map<Integer, TenantProduct> productMap = productFacade.page(new PageParams<>()).getRecords().stream().collect(Collectors.toMap(TenantProduct::getId, o -> o));
        pageResponse.getRecords().forEach(item -> item.setProduct(productMap.get(item.getProductId())));

        return pageResponse;
    }

    @Override
    public TenantDevice queryOne(int id) {

        TenantDevice device = deviceService.getById(id);

        device.setProduct(productFacade.queryOne(device.getProductId()));

        return device;
    }

    @Override
    public TenantDevice saveOrUpdate(TenantDevice entity) {

        // 若是需要更新，校验是否存在此id的设备
        if (entity.getId() != null && entity.getId() != 0 && deviceService.getById(entity.getId()) == null) {
            throw new BizExp("不存在的设备！");
        }

        // 校验产品
        if (entity.getProductId() == null || productService.getById(entity.getProductId()) == null) {
            throw new BizExp("不得绑定不存在或已被删除的产品！");
        }

        // 校验重复
        QueryWrapper<TenantDevice> deviceQueryWrapper = new QueryWrapper<>();
        deviceQueryWrapper.lambda()
                .ne(entity.getId() != null && entity.getId() != 0, TenantDevice::getId, entity.getId())
                .eq(TenantDevice::getIpAddr, entity.getIpAddr());

        if (deviceService.count(deviceQueryWrapper) != 0) {
            throw new BizExp("此IP已被占用！");
        }

        // 生成32位唯一编码
        if (entity.getId() == null || entity.getId() == 0) {
            entity.setTenantId(CurUserCtx.get().getTenantId());
            String uniqueCode = UUID.fastUUID().toString(true);
            entity.setUniqueCode(uniqueCode);
        }

        if (!deviceService.saveOrUpdate(entity)) {
            throw new BizExp("保存设备时出现未知错误！");
        }

        log.info("保存设备 => {}", entity);
        return queryOne(entity.getId());
    }

    @Override
    public TenantDevice remove(int id) {

        TenantDevice device = queryOne(id);

        if (!deviceService.removeById(id)) {
            throw new BizExp("删除设备时发生错误！");
        }

        log.info("删除设备 => {}", device);
        return device;
    }

    @Override
    public Boolean batchRemove(List<Integer> idList) {

        boolean flag = deviceService.removeByIds(idList);

        if (!flag) {
            throw new BizExp("批量删除设备失败");
        }

        log.info("批量删除设备 => {}", idList);
        return true;
    }

    @Override
    public Boolean batchSave(List<TenantDevice> entities) {
        return null;
    }

    @Override
    public List<RadioDataItem> queryDeviceOfProductForRadio() {

        return deviceService.queryDeviceOfProductForRadio();
    }

    @Override
    public TenantDevice queryOneByUniqueCode(String uniqueCode) {
        // 获取设备信息
        QueryWrapper<TenantDevice> deviceQueryWrapper = new QueryWrapper<>();
        deviceQueryWrapper
                .lambda()
                .select(TenantDevice::getId)
                .eq(TenantDevice::getUniqueCode, uniqueCode);

        TenantDevice device = deviceService.getOne(deviceQueryWrapper);

        if (device == null) {
            throw new BizExp("此设备不存在或已被删除");
        }

        return queryOne(device.getId());
    }

    @Override
    public TenantDevice queryOneByIp(Integer tenantId, String deviceIpAddr) {

        Object o = redisUtil.get(deviceDetailRedisKey + ":" + tenantId + ":" + deviceIpAddr);
        if (o != null) {
            return JSONUtil.toBean(o.toString(), TenantDevice.class);
        }

        // 获取设备信息
        QueryWrapper<TenantDevice> deviceQueryWrapper = new QueryWrapper<>();
        deviceQueryWrapper
                .lambda()
                .select(TenantDevice::getId)
                .eq(TenantDevice::getIpAddr, deviceIpAddr);

        TenantDevice device = deviceService.getOne(deviceQueryWrapper);

        if (device == null) {
            log.warn("不存在的设备ip {}", deviceIpAddr);
            return null;
        }

        TenantDevice res = queryOne(device.getId());
        redisUtil.set(deviceDetailRedisKey + ":" + tenantId + ":" + deviceIpAddr, JSONUtil.toJsonStr(res));
        return res;
    }
}
